/***********************************************************************************
 * The MIT License (MIT)
 * Copyright (c) 2014 Robin Chutaux
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * **********************************************************************************/

package com.hendraanggrian.recyclerview.widget;


import com.hendraanggrian.recyclerview.ResourceTable;

import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.app.dispatcher.task.Revocable;

/**
 * ExpandableItem
 */
public class ExpandableItem extends DependentLayout {
    private StackLayout contentLayout;
    private StackLayout headerLayout;
    private int duration;
    private boolean closeByUser = true;
    private boolean isAnimationRunning = false;
    private boolean isOpened = false;
    private int initialContentHeight = 0;

    public ExpandableItem(Context context) {
        super(context);
    }

    public ExpandableItem(Context context, AttrSet attrs) {
        super(context, attrs);
        final LayoutScatter layoutScatter = LayoutScatter.getInstance(context);
        layoutScatter.parse(ResourceTable.Layout_widget_expandableitem, this, true);
        headerLayout = (StackLayout) findComponentById(ResourceTable.Id_widget_expandableitem_headerlayout);
        contentLayout = (StackLayout) findComponentById(ResourceTable.Id_widget_expandableitem_contentlayout);
        duration = AttrUtils.getIntegerFromAttr(attrs, "duration", 200);
        final int headerId = AttrUtils.getLayoutIdFormAttr(attrs, "layoutHeader", -1);
        final int contentId = AttrUtils.getLayoutIdFormAttr(attrs, "layoutContent", -1);
        if (headerId == -1 || contentId == -1) {
            throw new IllegalArgumentException("HeaderLayout and ContentLayout cannot be null!");
        }
        final Component headerView = layoutScatter.parse(headerId, headerLayout, false);
        headerView.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_CONTENT));
        headerLayout.addComponent(headerView);
        final Component contentView = layoutScatter.parse(contentId, contentLayout, false);
        contentView.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_CONTENT));
        contentLayout.addComponent(contentView);
        contentLayout.estimateSize(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_CONTENT);
        context.getUITaskDispatcher().delayDispatch(() ->
                initialContentHeight = contentView.getEstimatedHeight(), 1);
        contentLayout.setVisibility(Component.HIDE);
        setId(ResourceTable.String_expandableItem_id);
    }

    private void expand(final Component component) {
        isOpened = true;
        component.setHeight(0);
        component.setVisibility(VISIBLE);
        final AnimatorValue animation = new AnimatorValue();
        animation.setValueUpdateListener((animatorValue1, interpolatedTime) -> {
            int height = (interpolatedTime == 1)
                    ? initialContentHeight
                    : (int) (initialContentHeight * interpolatedTime);
            component.setHeight(height);
            component.postLayout();
        });
        animation.setDuration(duration);
        animation.start();
    }

    private void collapse(final Component component) {
        isOpened = false;
        final AnimatorValue animation = new AnimatorValue();
        animation.setValueUpdateListener((animatorValue1, interpolatedTime) -> {
            if (interpolatedTime == 1) {
                component.setVisibility(HIDE);
                isOpened = false;
            } else {
                int height = initialContentHeight -
                        (int) (initialContentHeight * interpolatedTime);
                component.setHeight(height);
                component.postLayout();
            }
        });
        animation.setDuration(duration);
        animation.start();
    }

    /**
     * 立即隐藏
     */
    public void hideNow() {
        contentLayout.getLayoutConfig().height = 0;
        contentLayout.setVisibility(HIDE);
        isOpened = false;
    }

    /**
     * 立即显示
     */
    public void showNow() {
        if (!isOpened) {
            contentLayout.setVisibility(VISIBLE);
            isOpened = true;
            contentLayout.getLayoutConfig().height = LayoutConfig.MATCH_CONTENT;
        }
    }

    /**
     * 显示
     */
    public void show() {
        if (!isAnimationRunning) {
            expand(contentLayout);
            isAnimationRunning = true;
            Revocable revocable = getContext().getUITaskDispatcher().delayDispatch(new Runnable() {
                @Override
                public void run() {
                    isAnimationRunning = false;
                }
            }, duration);
        }
    }

    /**
     * 隐藏
     */
    public void hide() {
        if (!isAnimationRunning) {
            collapse(contentLayout);
            isAnimationRunning = true;
            getContext().getUITaskDispatcher().delayDispatch(new Runnable() {
                @Override
                public void run() {
                    isAnimationRunning = false;
                }
            }, duration);
        }
        closeByUser = false;
    }

    /**
     * 设置动画时长
     *
     * @param duration 动画持续时间
     */
    public void setDuration(int duration) {
        this.duration = duration;
    }

    /**
     * 获取动画时长
     *
     * @return int duration
     */
    public int getDuration() {
        return duration;
    }

    /**
     * 获取getHeaderLayout
     *
     * @return ComponentContainer headerLayout
     */
    public ComponentContainer getHeaderLayout() {
        return headerLayout;
    }

    /**
     * 获取ContentLayout
     *
     * @return ComponentContainer contentLayout
     */
    public ComponentContainer getContentLayout() {
        return contentLayout;
    }

    /**
     * 是否展开
     *
     * @return isOpened
     */
    public boolean isOpened() {
        return isOpened;
    }

    /**
     * 是否是用户关闭
     *
     * @return boolean closeByUser
     */
    public boolean isClosedByUser() {
        return closeByUser;
    }


}